package kibahed.uni.charts;


import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.swing.ImageIcon;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;

import org.apache.batik.dom.GenericDOMImplementation;
import org.apache.batik.svggen.SVGGraphics2D;
import org.apache.xmlgraphics.java2d.ps.EPSDocumentGraphics2D;
import org.jfree.chart.JFreeChart;
import org.w3c.dom.DOMImplementation;



@XmlRootElement
public abstract class AKChart {

	public static final Integer panelView = 10;
	public static final Integer frameView = 20;

	public static final Integer lengthDeviationChart = 100;
	public static final Integer avgPathLengthChart = 110;
	public static final Integer pheromonMatrixVisualisation = 120;
	public static final Integer tourChart = 130;
	public static final Integer lambdaFactorChart = 140;
	public static final Integer shortestTourLengthChart = 150;
	public static final Integer acsgaFitnessChart = 160;
	public static final Integer distanceBetweenToursChart = 170;

	public static final Integer onlyFittedValues = 200;
	public static final Integer onlyDataPoints = 210;
	public static final Integer fittedValuesAndDataPoints = 230;
	public static final Integer reportStyle = 240;
	public static final Integer trueLinePlusPoints = 250;
	public static final Integer meanAndDeviationLine = 260;

	private String path;
	protected String title;
	protected JFreeChart chart;
	protected String fileName = "chart";

	protected String[] valueNames;
	protected String[] fittedValueNames;
	protected String xAxisName = "Iteration";
	protected String yAxisName = "y-Value";

	protected Font titleFont;
	protected Font xAxisValueFont;
	protected Font yAxisValueFont;
	protected Font xAxisLabelFont;
	protected Font yAxisLabelFont;
	protected Font legendFont;

	protected List<Color> colors;
	protected List<Shape> shapes;

	@XmlAnyElement(lax = true)
	public List<XYDataPairList> dataPairLists = new LinkedList<XYDataPairList>();

	public void setTitle(String title) {
		this.title = title;
	}

	public String getTitle() {
		return title;
	}

	public abstract void setInfo(List<String> infos);

	public abstract List<String> getInfos();

	public abstract void addData(List<Object> data);
	
	public abstract void addXYDataPair(XYDataPair dataPair);

	public abstract List<Integer> getData();

	public abstract void generateChart(Integer view);

	public abstract void setChartType(Integer chartType);

	public abstract Integer getChartType();

	public abstract void setDrawingMode(Integer drawingMode);

	public abstract Integer getDrawingMode();

	public abstract void startNewXYDataPairList();

	public String getPath() {
		return path;
	}

	public void setPath(String path) {
		this.path = path;
	}

	public void saveChart() {

		Rectangle2D bounds = new Rectangle2D.Double(0, 0, 1200, 800);

		File svgFile = new File(path + "/" + fileName + ".svg");
		File epsFile = new File(path + "/" + fileName + ".eps");
		File tourFile = new File(path + "/"+ "tour" +".eps");
		
		System.out.println(epsFile.toString());
		
		System.out.println(tourFile.toString());
		
		valdidatePanel();
		
		try {
			exportChartAsSVG(chart, bounds, svgFile);

		} catch (IOException e) {

			e.printStackTrace();
		}
		
		try {
			saveAsEPS(chart, epsFile, bounds);
		} catch (Exception e1) {

			e1.printStackTrace();
		} 
	}

	/**
	 * Exports a JFreeChart to a SVG file.
	 * 
	 * @param chart
	 *            JFreeChart to export
	 * @param bounds
	 *            the dimensions of the viewport
	 * @param svgFile
	 *            the output file.
	 * @throws IOException
	 *             if writing the svgFile fails.
	 */
	public void exportChartAsSVG(JFreeChart chart, Rectangle2D bounds,
			File svgFile) throws IOException {
		// Get a DOMImplementation and create an XML document
		DOMImplementation domImpl = GenericDOMImplementation
				.getDOMImplementation();
		org.w3c.dom.Document document = domImpl.createDocument(null, "svg",
				null);

		// Create an instance of the SVG Generator
		SVGGraphics2D svgGenerator = new SVGGraphics2D(
				(org.w3c.dom.Document) document);

		// draw the chart in the SVG generator
		chart.draw(svgGenerator, bounds);

		// Write svg file
		java.io.OutputStream outputStream = new FileOutputStream(svgFile);
		OutputStreamWriter out = new OutputStreamWriter(outputStream, "UTF-8");
		svgGenerator.stream(out, true);
		outputStream.flush();
		outputStream.close();
	}

	public void saveAsEPS(JFreeChart chart, File outfile, Rectangle2D bounds)
			throws Exception {

		System.out.println("Saving as EPS");
		FileOutputStream out = new FileOutputStream(outfile);
		EPSDocumentGraphics2D g2d = new EPSDocumentGraphics2D(true);
		g2d.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext());

		g2d.setupDocument(out, 1200, 800); // 400pt x 200pt
		chart.draw(g2d, bounds);
		
	
		
		g2d.finish();
		out.flush();
		out.close();

	}

	public void saveTourVisualisation(Graphics2D tour, File outfile, Rectangle2D bounds) throws Exception {
		
		System.out.println("Saving tour as EPS"); 
		FileOutputStream out = new FileOutputStream(outfile);
		EPSDocumentGraphics2D g2d = new EPSDocumentGraphics2D(false);
		g2d.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext());
		
		
		
		g2d.setupDocument(out, 400, 400);
		
		
	
		g2d.drawRect(0, 0, 400, 400);
		
		g2d.setComposite(tour.getComposite());
		
         g2d.setFont(new Font("sans-serif", Font.BOLD, 14));
         g2d.drawString("Color usage example:", 10, 20);
         g2d.setFont(new Font("sans-serif", Font.PLAIN, 12));
         g2d.drawString("RGB", 10, 84);
         g2d.drawString("CMYK", 60, 84);
         g2d.drawString("(Lab)", 110, 84);
         g2d.drawString("(Named)", 160, 84);
		
		
		g2d.finish();
		out.flush();
		out.close();
		
	}
	
	public JFreeChart getChart() {
		return chart;
	}

	@XmlTransient
	public void setChart(JFreeChart chart) {
		this.chart = chart;
	}

	public void saveToXML(AKChart r) {

		System.out.println("Started Saving");
		if (path == null) {
			path = "d:/Dokumente/";
		}
		if (title == null) {
			title = "chartData";
		}

		File file = new File(path + "/" + fileName);
		JAXBContext jc;
		try {
			jc = getJAXBContext();

			Marshaller m = jc.createMarshaller();
			m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
			try {

				m.marshal(
						r,
						new FileOutputStream(file.getPath().replaceAll(".xml",
								"")
								+ ".xml"));

			} catch (FileNotFoundException ex) {
				System.out.println("FileNotFoundException: " + ex.toString());
			}
		} catch (JAXBException ex) {
			System.err.println("JAXBException: " + ex.toString());
		}
		System.out.println("Saving Finisehd");
	}

	public static AKChart loadFromFile(File file) {
		JAXBContext jc;
		AKChart r = null;
		
		try {
			jc = getJAXBContext();
			Unmarshaller um = jc.createUnmarshaller();
			r = (ComplexChart) um.unmarshal(file);

		} catch (Exception e) {
			System.out.println(e.toString());
		}
		
		return r;
	}

	public static AKChart loadFromPath(String path) {
		JAXBContext jc;
		AKChart r = null;
		try {
			jc = getJAXBContext();
			Unmarshaller um = jc.createUnmarshaller();
			File xml = new File(path + ".xml");
			r = (AKChart) um.unmarshal(xml);

		} catch (Exception e) {
			System.out.println(e.toString());
		}
		return r;
	}

	private static JAXBContext getJAXBContext() throws JAXBException {

		JAXBContext context = null;

		Class[] classArray = new Class[5];
		classArray[1] = AKChart.class;
		classArray[0] = SimpleChart.class;
		classArray[2] = XYDataPairList.class;
		classArray[3] = XYDataPair.class;
		classArray[4] = ComplexChart.class;
		
		Map<String, Integer> propterties = new HashMap<String, Integer>();
		context = JAXBContext.newInstance(classArray, propterties);

		return context;
	}

	public void setFileName(String fileName) {
		this.fileName = fileName;
	}

	public String getFileName() {
		return fileName;
	}

	@XmlTransient
	public Font getTitleFont() {
		return titleFont;
	}

	public void setTitleFont(Font titleFont) {
		this.titleFont = titleFont;
	}

	@XmlTransient
	public Font getxAxisValueFont() {
		return xAxisValueFont;
	}

	public void setxAxisValueFont(Font xAxisValueFont) {
		this.xAxisValueFont = xAxisValueFont;
	}

	@XmlTransient
	public Font getyAxisValueFont() {
		return yAxisValueFont;
	}

	public void setyAxisValueFont(Font yAxisValueFont) {
		this.yAxisValueFont = yAxisValueFont;
	}

	@XmlTransient
	public Font getxAxisLabelFont() {
		return xAxisLabelFont;
	}

	public void setxAxisLabelFont(Font xAxisLabelFont) {
		this.xAxisLabelFont = xAxisLabelFont;
	}

	@XmlTransient
	public Font getyAxisLabelFont() {
		return yAxisLabelFont;
	}

	public void setyAxisLabelFont(Font yAxisLabelFont) {
		this.yAxisLabelFont = yAxisLabelFont;
	}

	@XmlTransient
	public Font getLegendFont() {
		return legendFont;
	}

	public void setLegendFont(Font legendFont) {
		this.legendFont = legendFont;
	}

	public String[] getValueNames() {
		return valueNames;
	}

	public void setValueNames(String[] valueNames) {
		this.valueNames = valueNames;
	}

	public String[] getFittedValueNames() {
		return fittedValueNames;
	}

	public void setFittedValueNames(String[] fittedValueNames) {
		this.fittedValueNames = fittedValueNames;
	}

	public String getxAxisName() {
		return xAxisName;
	}

	public void setxAxisName(String xAxisName) {
		this.xAxisName = xAxisName;
	}

	public String getyAxisName() {
		return yAxisName;
	}

	public void setyAxisName(String yAxisName) {
		this.yAxisName = yAxisName;
	}

	
	// only use screw degrees;
	protected double[] getSmoothedValues(double[] values, int degree) {

		if (degree % 2 == 0)
			degree++;

		double[] smoothValues = new double[values.length];

//		for (int i = 0; i < degree / 2; i++) {
//			smoothValues[i] = values[i];
//		}
//
//		for (int i = values.length - degree / 2; i < values.length; i++) {
//			smoothValues[i] = values[i];
//		}
//		for(int i = 0; i < values.length; i++) {
//			smoothValues[i] = values[i];
//		}
//		
		// TODO
		for(int i = 0; i < values.length-degree; i++) {
			
			int s = 0; 
			for(int j = i; j < i+degree; j++) {
				s += values[j];
			}
			smoothValues[i] = s / (double)degree;
			
		}
		
		for(int i = values.length-degree; i < values.length; i++) {
			smoothValues[i] = values[i];
		}
		
//		for (int i = degree / 2; i < values.length - degree / 2; i++) {
//			int s = 0;
//			for (int j = i - degree / 2; j <= i + degree / 2; j++) {
//				s += values[j];
//			}
//			smoothValues[i] = s / (double) degree;
//		}

		return smoothValues;
	}

	public void setFonts() {
		Font titleFont = new Font(Font.SERIF, Font.PLAIN, 50);
		Font valueFont = new Font(Font.SERIF, Font.PLAIN, 40);
		Font labelFont = new Font(Font.SERIF, Font.PLAIN, 60);
		Font legendFont = new Font(Font.SERIF, Font.PLAIN, 40);

		setTitleFont(titleFont);
		setxAxisLabelFont(labelFont);
		setyAxisLabelFont(labelFont);
		setxAxisValueFont(valueFont);
		setyAxisValueFont(valueFont);
		setLegendFont(legendFont);

	}
	
	public abstract void valdidatePanel();
}
